package com.me.study.producerAndConsumer;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 使用 wait/notify 的生产者/消费者<p>
 * 条件变更产生的问题
 *
 * @author ME
 * @date   2019/3/6 16:05
 */
public class WaitNotifyCountDown {

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(15);
        List<Integer> list = new ArrayList(8);
        ExecutorService executor = Executors.newFixedThreadPool(15);

        for (int i = 0; i < 5; i++) {
            executor.submit(new Producer(countDownLatch, list, i));
            countDownLatch.countDown();
        }
        for (int i = 0; i < 10; i++) {
            executor.submit(new Consumer(countDownLatch, list, i));
            countDownLatch.countDown();
        }
    }


    static class Consumer implements Runnable {
        private CountDownLatch countDownLatch;
        private List<Integer> list;
        private int name;

        public Consumer(CountDownLatch countDownLatch, List list, int i) {
            this.countDownLatch = countDownLatch;
            this.list = list;
            this.name = i;
        }

        @Override
        public void run() {
            Thread.currentThread().setName("消费者" + name);

            try {
                countDownLatch.await();
                while (true) {
                    synchronized (list) {
                        /**
                         * 这里使用 if 的话，就会存在wait条件变化造成程序错误的问题?
                         * TODO 因为线程唤醒之后是接着往下执行的，如果是 if 的话 remove 2次会下标越界
                         */
                        while (list.isEmpty()) {
                            System.out.println(Thread.currentThread().getName() + "  list为空，进行wait");
                            list.wait();
                            System.out.println(Thread.currentThread().getName() + "  退出wait");
                        }
                        Integer element = list.remove(0);
                        System.out.println(Thread.currentThread().getName() + "  消费数据：" + element);
                        list.notifyAll();
                        System.out.println(Thread.currentThread().getName() + "  退出wait");
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    static class Producer implements Runnable {
        private CountDownLatch countDownLatch;
        private List<Integer> list;
        private int name;
        private int maxLength = 8;

        public Producer(CountDownLatch countDownLatch, List list, int i) {
            this.countDownLatch = countDownLatch;
            this.list = list;
            this.name = i;
        }

        @Override
        public void run() {
            Thread.currentThread().setName("生产者" + name);

            try {
                countDownLatch.await();
                while (true) {
                    synchronized (list) {
                        while (list.size() == maxLength) {
                            System.out.println(Thread.currentThread().getName() + "  list以达到最大容量，进行wait");
                            list.wait();
                            System.out.println(Thread.currentThread().getName() + "  退出wait");
                        }
                        Random random = new Random();
                        int i = random.nextInt();
                        list.add(i);
                        System.out.println(Thread.currentThread().getName() + " 生产数据" + i);
                        list.notifyAll();
                        System.out.println(Thread.currentThread().getName() + "  退出wait");
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}
